package com.yc.utilslib.reader.protocol;

import com.yc.utilslib.reader.protocol.tagvalue.Field;
import com.yc.utilslib.reader.protocol.tagvalue.Tag;
import com.yc.utilslib.utils.ByteUtils;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 作者：TanTun
 * 时间：2017/10/18
 * 邮箱：32965926@qq.com
 * 描述：协议命令字枚举
 */

public class Command {
    private Cmd cmd;
    private Map<Tag, Field> fieldArray;

    public Cmd getCmd() {
        return cmd;
    }

    public void setCmd(Cmd cmd) {
        this.cmd = cmd;
    }

    public Map<Tag, Field> getFieldArray() {
        return fieldArray;
    }

    private Command(Cmd cmd) {
        this.cmd = cmd;
        this.fieldArray = new HashMap<>();
    }

    public Command(Cmd cmd, Map<Tag, Field> fieldArray) {
        this.cmd = cmd;
        this.fieldArray = fieldArray;
    }

    public static Command parsing(byte[] data) {
        Cmd cmd = Cmd.getCmd(data[3]);

        Command command = new Command(cmd);

        int index = 4;

        while (index < (data[2] & 0x0FF) + 4)
        {
            Tag tag = Tag.getTag(ByteUtils.byteArrayToShort(data, index, ByteUtils.Endian.Big));
            index = index + 2;

            int len = ByteUtils.byteArrayToShort(data, index, ByteUtils.Endian.Big);
            index = index + 2;

            byte[] value = new byte[len];
            System.arraycopy(data, index, value, 0, len);
            index = index + len;

            if (len != 0)
            {
                assert tag != null;
                //Object obj = tag.byteArrayToValue(value);
                //Field field = Field.getInstance(tag, obj);
                Field field = Field.getInstance(tag, value);
                if (field != null) command.fieldArray.put(tag, field);
            }
        }

        return command;
    }

    public byte[] toArray() {

        byte[] values = getFieldBytes();

        ByteBuffer crcBuffer = ByteBuffer.allocate(values.length + 2);
        crcBuffer.put((byte)(values.length & 0xFF));
        crcBuffer.put(cmd.getValue());
        crcBuffer.put(values);
        byte[] tmp = crcBuffer.array();
        int crc = ByteUtils.calculationCRC(tmp, 0, tmp.length);

        ByteBuffer array = ByteBuffer.allocate(tmp.length + 5);
        array.put(Defines.PROTOCOL_HEADING1);
        array.put(Defines.PROTOCOL_HEADING2);
        array.put(tmp);
        array.put((byte)(crc & 0xFF));
        array.put(Defines.PROTOCOL_ENDING1);
        array.put(Defines.PROTOCOL_ENDING2);

        return array.array();
    }

    private byte[] getFieldBytes() {

        if (fieldArray == null || fieldArray.size() == 0) return new byte[0];

        List<ByteBuffer> list = new ArrayList<>();
        int length = 0;

        for (Map.Entry<Tag, Field> entry : fieldArray.entrySet()
             ) {
            byte[] tag = ByteUtils.shortToByteArray(entry.getKey().getValue());
            byte[] value = entry.getKey().valueToByteArray(entry.getValue().getValue());
            byte[] len = ByteUtils.shortToByteArray(entry.getKey().getLength());
            assert value != null;
            length = length + tag.length + value.length + len.length;
            ByteBuffer item = ByteBuffer.allocate(tag.length + value.length + len.length);

            item.put(tag);
            item.put(len);

            for (byte b : value
                ){
                item.put(b);
            }

            list.add(item);
        }

        ByteBuffer buffer = ByteBuffer.allocate(length);
        for (ByteBuffer item : list
             ) {
            buffer.put(item.array());
        }

        return buffer.array();
    }
}
